using System;
using System.Security.Cryptography;
using System.Text;

using log4net;

namespace GymManager.Mechanism
{
    /// <summary>
    /// Class responsible by providing methods to encrypt and decrypt
    /// strings using 3DES algorithm with MD5 hashing
    /// </summary>
    public class CriptographyManager
    {
        // key used to apply on cryptographic alghoritm
        private static readonly String CRYPTOGRAPHY_KEY = "ART&FORMA";

        // logger instance
        private static ILog _logManager = LogManager.GetLogger(typeof(CriptographyManager));

        /// <summary>
        /// Method responsible by encrypting information.
        /// </summary>
        /// <remarks>
        /// This method uses TripleDES algorith with md5 hashing.
        /// The final chain is converted to Base 64.
        /// </remarks>
        /// <param name="String"> information to be encrypted </param>
        /// <returns>String encrypted information</returns>
        public static String encrypt(String plainInformation)
        {
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("Begin Method");
            }

            // encrypted information to be returned
            byte[] encryptedInformationArray = null;

            // hashing key information with md5
            byte[] keyArray = null;
            MD5CryptoServiceProvider md5Hash = new MD5CryptoServiceProvider();
            keyArray = md5Hash.ComputeHash(UTF8Encoding.UTF8.GetBytes(CRYPTOGRAPHY_KEY));
            md5Hash.Clear();

            // information to be encrypted
            byte[] plainInformationArray = UTF8Encoding.UTF8.GetBytes(plainInformation);

            // setting cryptography parameters
            TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
            cryptoProvider.Key = keyArray;
            cryptoProvider.Mode = CipherMode.ECB; // ECB(Eletronic Code Book) Mode
            cryptoProvider.Padding = PaddingMode.PKCS7; //padding mode(if any extra byte added)

            // encrypting information
            ICryptoTransform cryptoTransform = cryptoProvider.CreateEncryptor();
            encryptedInformationArray = cryptoTransform.TransformFinalBlock(plainInformationArray, 0, plainInformationArray.Length);

            //Release resources held by TripleDes Encryptor
            cryptoProvider.Clear();

            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("End Method");
            }

            //Return the encrypted data into unreadable string format
            return Convert.ToBase64String(encryptedInformationArray);
        }

        /// <summary>
        /// Method responsible by decrypting information.
        /// </summary>
        /// <remarks>
        /// This method uses TripleDES algorith with MD5 hashing.
        /// The final chain is converted to Base 64.
        /// </remarks>
        /// <param name="String"> information to be decrypted </param>
        /// <returns>String decrypted information</returns>
        public static String decrypt(String encryptedInformation)
        {
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("Begin Method");
            }

            // encrypted information to be returned
            byte[] plainInformationArray = null;

            // hashing key information with md5
            byte[] keyArray = null;
            MD5CryptoServiceProvider md5Hash = new MD5CryptoServiceProvider();
            keyArray = md5Hash.ComputeHash(UTF8Encoding.UTF8.GetBytes(CRYPTOGRAPHY_KEY));
            md5Hash.Clear();

            // information to be encrypted
            byte[] encryptedInformationArray = Convert.FromBase64String(encryptedInformation);

            // setting cryptography parameters
            TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
            cryptoProvider.Key = keyArray;
            cryptoProvider.Mode = CipherMode.ECB; // ECB(Eletronic Code Book) Mode
            cryptoProvider.Padding = PaddingMode.PKCS7; //padding mode(if any extra byte added)

            // decrypting information
            ICryptoTransform decryptoTransform = cryptoProvider.CreateDecryptor();
            plainInformationArray = decryptoTransform.TransformFinalBlock(encryptedInformationArray, 0, encryptedInformationArray.Length);

            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("End Method");
            }

            // return the Clear decrypted TEXT
            return UTF8Encoding.UTF8.GetString(plainInformationArray);
        }
    }
}
